package com.example.performance.r2dbc.entity.performance;

import com.example.performance.r2dbc.entity.RecordDb;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author zpMeng
 * @since 7/21/2025
 */
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Benchmark)
@Warmup(iterations = 10, time = 50, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 10, time = 50, timeUnit = TimeUnit.MILLISECONDS)
@Fork(1)
public class PerformanceTest {

    public static final DataSource dataSource = DataSourceBuilder
            .create()
            .url("jdbc:postgresql://10.86.0.7:5432/fmuser_atlas_demo")
            .username("fmuser_atlas_demo")
            .password("fm")
            .build();
    public static final JdbcTemplate JDBC_TEMPLATE = new JdbcTemplate(dataSource);

    private static final List<String> allFields = List.of(
            "ID_COMMANDE",
            "DATE_EXPED_DEMAND",
            "QTE_COMMANDE",
            "ID_CLIENT",
            "DATE_DLUO",
            "DATE_PROD",
            "QTE_LIVRE",
            "DATE_LIVRAISON",
            "DATE_PROD_INIT",
            "QTE_RELIQUAT",
            "TEXT1",
            "TEXT2",
            "TEXT3",
            "TEXT4",
            "TEXT5",
            "TEXT6",
            "TEXT7",
            "TEXT8",
            "TEXT9",
            "TEXT10",
            "QTY1",
            "QTY2",
            "QTY3",
            "QTY4",
            "QTY5",
            "QTY6",
            "QTY7",
            "QTY8",
            "QTY9",
            "QTY10",
            "DATE1",
            "DATE2",
            "DATE3",
            "DATE4",
            "DATE5",
            "DATE6",
            "DATE7",
            "DATE8",
            "DATE9",
            "DATE10"
    );

    //@Benchmark
    public void queryAllColumns(Blackhole blackhole) {
        List<RecordDb> query = JDBC_TEMPLATE.query("""
                        select
                            *
                        from
                            DS_AGG_427_0
                        where node_id <= 1000
                        """,
                new AllRecordRowMapper());

        blackhole.consume(query);
    }

    @Benchmark
    public void queryAllColumnsByIndex(Blackhole blackhole) {
        List<RecordDb> query = JDBC_TEMPLATE.query("""
                        select
                            *
                        from
                            DS_AGG_427_0
                        where node_id <= 1000
                        """,
                new AllRecordRowMapperByIndex());

        blackhole.consume(query);
    }

    //@Benchmark
    public void queryAllVisibleColumns(Blackhole blackhole) {
        List<RecordDb> query = JDBC_TEMPLATE.query("""
                        select
                            *
                        from 
                            DS_AGG_427_0
                        where node_id <= 1000
                        """,
                new VisibleRecordRowMapper(allFields));

        blackhole.consume(query);
    }

    //@Benchmark
    public void queryAllVisibleColumnsByIndex(Blackhole blackhole) {
        List<RecordDb> query = JDBC_TEMPLATE.query("""
                        select
                            *
                        from 
                            DS_AGG_427_0
                        where node_id <= 1000
                        """,
                new VisibleRecordRowMapperByIndex(allFields));

        blackhole.consume(query);
    }

    private static String ALL_SQL = """
                        select
                            DS_ID,
                            NODE_ID,
                            STATUT,
                            %s
                        from
                            DS_AGG_427_0
                        where node_id <= 1000
                        """.formatted(String.join(",\n", allFields));

    @Benchmark
    public void queryAllVisibleColumnsByEnumIndex(Blackhole blackhole) {
        List<RecordDb> query = JDBC_TEMPLATE.query(
                ALL_SQL,
                new VisibleRecordRowMapperByEnumAndIndex(allFields));

        blackhole.consume(query);
    }

    @Benchmark
    public void queryAllVisibleColumnsByEnumIndex3(Blackhole blackhole) {
        List<RecordDb> query = JDBC_TEMPLATE.query(
                ALL_SQL,
                new VisibleRecordRowMapperByEnumAndIndex3(allFields));

        blackhole.consume(query);
    }

    //@Benchmark
    public void queryMinVisibleColumns(Blackhole blackhole) {
        List<RecordDb> query = JDBC_TEMPLATE.query("""
                        select
                            DS_ID,
                            NODE_ID,
                            STATUT,
                            ID_COMMANDE,
                            DATE_EXPED_DEMAND,
                            QTE_COMMANDE
                        from 
                            DS_AGG_427_0
                        where node_id <= 1000
                        """,
                new VisibleRecordRowMapperByEnumAndIndex(List.of(
                        "ID_COMMANDE",
                        "DATE_EXPED_DEMAND",
                        "QTE_COMMANDE"
                )));

        blackhole.consume(query);
    }

    private static final List<String> TWENTY_FIELDS = List.of(
            "ID_COMMANDE",
            "DATE_EXPED_DEMAND",
            "QTE_COMMANDE",
            "ID_CLIENT",
            "DATE_DLUO",

            "DATE_PROD",
            "QTE_LIVRE",
            "DATE_LIVRAISON",
            "DATE_PROD_INIT",
            "QTE_RELIQUAT",

            "TEXT1",
            "TEXT2",
            "TEXT3",
            "TEXT4",
            "TEXT5",

            "QTY1",
            "QTY2",
            "QTY3",
            "QTY4",
            "QTY5"
    );

    public static String TWENTY_SQL = """
            select
                DS_ID,
                NODE_ID,
                STATUT,
                %s
            from
                DS_AGG_427_0
            where node_id <= 1000
            """.formatted(String.join(",\n", TWENTY_FIELDS));

    //@Benchmark
    public void queryTwentyVisibleColumns(Blackhole blackhole) {
        List<RecordDb> query = JDBC_TEMPLATE.query(TWENTY_SQL,
                new VisibleRecordRowMapperByEnumAndIndex(TWENTY_FIELDS));

        blackhole.consume(query);
    }

}
